#pragma once

#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<unordered_map>
#include<regex>
#include<ctype.h>
#include<sys/stat.h>
#include<sys/types.h>
#include "../source/server.hpp"

std::unordered_map<int, std::string> statu_msg_ = {
    {100,  "Continue"},
    {101,  "Switching Protocol"},
    {102,  "Processing"},
    {103,  "Early Hints"},
    {200,  "OK"},
    {201,  "Created"},
    {202,  "Accepted"},
    {203,  "Non-Authoritative Information"},
    {204,  "No Content"},
    {205,  "Reset Content"},
    {206,  "Partial Content"},
    {207,  "Multi-Status"},
    {208,  "Already Reported"},
    {226,  "IM Used"},
    {300,  "Multiple Choice"},
    {301,  "Moved Permanently"},
    {302,  "Found"},
    {303,  "See Other"},
    {304,  "Not Modified"},
    {305,  "Use Proxy"},
    {306,  "unused"},
    {307,  "Temporary Redirect"},
    {308,  "Permanent Redirect"},
    {400,  "Bad Request"},
    {401,  "Unauthorized"},
    {402,  "Payment Required"},
    {403,  "Forbidden"},
    {404,  "Not Found"},
    {405,  "Method Not Allowed"},
    {406,  "Not Acceptable"},
    {407,  "Proxy Authentication Required"},
    {408,  "Request Timeout"},
    {409,  "Conflict"},
    {410,  "Gone"},
    {411,  "Length Required"},
    {412,  "Precondition Failed"},
    {413,  "Payload Too Large"},
    {414,  "URI Too Long"},
    {415,  "Unsupported Media Type"},
    {416,  "Range Not Satisfiable"},
    {417,  "Expectation Failed"},
    {418,  "I'm a teapot"},
    {421,  "Misdirected Request"},
    {422,  "Unprocessable Entity"},
    {423,  "Locked"},
    {424,  "Failed Dependency"},
    {425,  "Too Early"},
    {426,  "Upgrade Required"},
    {428,  "Precondition Required"},
    {429,  "Too Many Requests"},
    {431,  "Request Header Fields Too Large"},
    {451,  "Unavailable For Legal Reasons"},
    {501,  "Not Implemented"},
    {502,  "Bad Gateway"},
    {503,  "Service Unavailable"},
    {504,  "Gateway Timeout"},
    {505,  "HTTP Version Not Supported"},
    {506,  "Variant Also Negotiates"},
    {507,  "Insufficient Storage"},
    {508,  "Loop Detected"},
    {510,  "Not Extended"},
    {511,  "Network Authentication Required"}
};

std::unordered_map<std::string, std::string> mime_msg_ = {
    {".aac",        "audio/aac"},
    {".abw",        "application/x-abiword"},
    {".arc",        "application/x-freearc"},
    {".avi",        "video/x-msvideo"},
    {".azw",        "application/vnd.amazon.ebook"},
    {".bin",        "application/octet-stream"},
    {".bmp",        "image/bmp"},
    {".bz",         "application/x-bzip"},
    {".bz2",        "application/x-bzip2"},
    {".csh",        "application/x-csh"},
    {".css",        "text/css"},
    {".csv",        "text/csv"},
    {".doc",        "application/msword"},
    {".docx",       "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
    {".eot",        "application/vnd.ms-fontobject"},
    {".epub",       "application/epub+zip"},
    {".gif",        "image/gif"},
    {".htm",        "text/html"},
    {".html",       "text/html"},
    {".ico",        "image/vnd.microsoft.icon"},
    {".ics",        "text/calendar"},
    {".jar",        "application/java-archive"},
    {".jpeg",       "image/jpeg"},
    {".jpg",        "image/jpeg"},
    {".js",         "text/javascript"},
    {".json",       "application/json"},
    {".jsonld",     "application/ld+json"},
    {".mid",        "audio/midi"},
    {".midi",       "audio/x-midi"},
    {".mjs",        "text/javascript"},
    {".mp3",        "audio/mpeg"},
    {".mpeg",       "video/mpeg"},
    {".mpkg",       "application/vnd.apple.installer+xml"},
    {".odp",        "application/vnd.oasis.opendocument.presentation"},
    {".ods",        "application/vnd.oasis.opendocument.spreadsheet"},
    {".odt",        "application/vnd.oasis.opendocument.text"},
    {".oga",        "audio/ogg"},
    {".ogv",        "video/ogg"},
    {".ogx",        "application/ogg"},
    {".otf",        "font/otf"},
    {".png",        "image/png"},
    {".pdf",        "application/pdf"},
    {".ppt",        "application/vnd.ms-powerpoint"},
    {".pptx",       "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
    {".rar",        "application/x-rar-compressed"},
    {".rtf",        "application/rtf"},
    {".sh",         "application/x-sh"},
    {".svg",        "image/svg+xml"},
    {".swf",        "application/x-shockwave-flash"},
    {".tar",        "application/x-tar"},
    {".tif",        "image/tiff"},
    {".tiff",       "image/tiff"},
    {".ttf",        "font/ttf"},
    {".txt",        "text/plain"},
    {".vsd",        "application/vnd.visio"},
    {".wav",        "audio/wav"},
    {".weba",       "audio/webm"},
    {".webm",       "video/webm"},
    {".webp",       "image/webp"},
    {".woff",       "font/woff"},
    {".woff2",      "font/woff2"},
    {".xhtml",      "application/xhtml+xml"},
    {".xls",        "application/vnd.ms-excel"},
    {".xlsx",       "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
    {".xml",        "application/xml"},
    {".xul",        "application/vnd.mozilla.xul+xml"},
    {".zip",        "application/zip"},
    {".3gp",        "video/3gpp"},
    {".3g2",        "video/3gpp2"},
    {".7z",         "application/x-7z-compressed"}
};

class Util
{
public:
      //字符串分割函数，将src字符串按照sep字符进行分割，得到的各个字串放到arry中，最终返回字串的数量
      static size_t Split(const std::string src,const std::string sep,std::vector<std::string>* v)
      {
            size_t offset=0;
            while  (offset<src.size())
            {
                  size_t pos=src.find(sep,offset);
                  if(pos==std::string::npos)
                  {
                        v->push_back(src.substr(offset));
                        return v->size();
                  }
                  if(pos!=offset)  v->push_back(src.substr(offset,pos-offset));
                  offset=pos+sep.size();
            }
            return v->size();
      }
      //读取文件的所有内容，将读取到的内容放到buf中
      static bool ReadFile(const std::string& filename,std::string* buf)
      {
            std::ifstream ifs(filename,std::ios::binary);
            if(ifs.is_open()==false)
            {
                printf("OPEN %s FILE FAILED!!", filename.c_str());
                return false;
            }
            
            int len;
            ifs.seekg(0,ifs.end);//跳转读写位置到末尾
            len=ifs.tellg();         //读取当前位置到文件起始位置的偏移量
            ifs.seekg(0,ifs.beg);//跳转读写位置到开始
            
            ifs.read(&(*buf)[0],len);
            if(ifs.good()==false)
            {
                  printf("READ %s FILE FAILED!!", filename.c_str());
                  ifs.close();
                  return false;
            }
            ifs.close();
            return true;
      }
      //向文件写入内容
      static bool WriteFile(const std::string& filename,const std::string buf)
      {
            std::ofstream  ofs(filename.c_str(),std::ios::binary|std::ios::trunc);
            if(ofs.is_open()==false)
            {
                  printf("OPEN %s FILE FAILED!!",filename.c_str());
                  return false;
            } 

            ofs.write(buf.c_str(),buf.length());
            if(ofs.good()==false)
            {
                  printf("WRITE %s FILE FAILED!!", filename.c_str());
                  ofs.close();
                  return false;
            }        
            ofs.close();
            return true;  
      }
      //URL编码，避免URL中资源路径与查询字符串中的特殊字符与HTTP请求中的特殊字符产生歧义
      //编码格式：将特殊字符的ASCII值转换为2个16进制字符，前缀%  C++ ->  %2B%2B
      //不编码的特殊字符，RFC3986文档规定 . - _ ~ 字母，数字属于绝对不编码字符
      //RFC3986文档规定，编码格式为%HH
      //W3C标准中规定，查询字符串中的空格，需要编码为+，解码则是+转空格
      static std::string UrlEncode(const std::string url,bool convert_space_to_plus)
      {
            std::string s;
            for(auto& ch:url)
            {
                  if(ch=='.'||ch=='-'||ch=='_'||ch=='~'||isalnum(ch))
                  {
                        s+=ch;
                        continue;
                  }
                  if(ch==' '&&convert_space_to_plus)
                  {
                        s+='+';
                        continue;
                  }
                  //剩下的字符都要要编码成%HH格式
                  char tmp[4]={0};
                  snprintf(tmp,4,"%%%02X",ch);
                  s+=tmp;
            }
            return s;
      }
      static char HEXTOI(char c)
      {
            if(c>='0'&&c<='9')
                  return c;
            else if(c>='a'&&c<='z')
                  return c-'a'+10;
            else if(c>='A'&&c<='Z')
                  return c-'A'+10;
            else 
                  return -1;
      }
      static std::string UrlDecode(const std::string url,bool convert_space_to_plus)
      {
            std::string s;
            for(int i=0;i<url.size();i++)
            {
                  //遇到了%，则将紧随其后的2个字符，转换为数字，第一个数字左移4位，然后加上第二个数字  + -> 2b  %2b->2 << 4 + 11
                  if(url[i]=='+'&&convert_space_to_plus)
                  {
                        s+=' ';
                        continue;
                  }
                  if(url[i]=='%'&&i+2<url.size())
                  {
                        char ch1=HEXTOI(url[i+1]);
                        char ch2=HEXTOI(url[i+2]);
                        char ch=ch1<<4+ch2;
                        s+=ch;
                        i+=2;
                        continue;
                  }
                  s+=url[i];
            }
            return s;   
      }
      //响应状态码的描述信息获取
      static std::string StatuDesc(int statu)
      {
            auto it=statu_msg_.find(statu);
            if(it==statu_msg_.end())
            {
                  return "Unknow";
            }
            return it->second;
      }
      //根据文件后缀名获取mime
      static std::string ExtMime(const std::string& filename)
      {
            size_t pos=filename.find_last_of('.');
            if(pos==std::string::npos)
            {
                  return "application/octet-stream";
            }
            std::string ext=filename.substr(pos);
            auto it=mime_msg_.find(ext);
            if(it==mime_msg_.end())
            {
                  return "application/octet-stream";
            }
            return it->second;
      }
      static bool IsDirectory(const std::string& filename)
      {
            struct  stat st;
            int n=stat(filename.c_str(),&st);
            if(n<0)
            {
                  return false;
            }       
            return S_ISDIR(st.st_mode);
      }
      static bool IsRegular(const std::string& filename)
      {
            struct stat st;
            int n=stat(filename.c_str(),&st);
            if(n<0)
            {
                  return false;
            }
            return S_ISREG(st.st_mode);
      }
      //HTTP请求的资源路径是否有效
      //客户端只能请求相对根目录的资源，其他地方的资源都不予理会
      static bool  VaildPath(const std::string& path)
      {
            std::vector<std::string> v;
            Split(path,"/",&v);
            int level=0;
            for(auto& s:v)
            {
                  if(s=="..")
                  {
                        level--;
                        if(level<0)  return false;
                        continue;
                  }
                  level++;
            }
            return true;
      }
};

class HttpRequest
{
public:
      std::string method_;          //请求方法
      std::string path_;             //资源路径
      std::string version_;         //协议版本
      std::string body_;            //请求正文
      std::smatch matches_;        //资源路径的正则提取数据
      std::unordered_map<std::string,std::string>     headers_;//头部字段
      std::unordered_map<std::string,std::string>     params_; //查询字符串
public:
      HttpRequest():version_("HTTP/1.1")
      {}
      void ReSet()
      {
            method_.clear();
            path_.clear();
            method_="HTTP/1.1";
            body_.clear();
            std::smatch math;
            math.swap(matches_);
            body_.clear();
            params_.clear();
      }
      //插入头部字段
      void SetHeader(const std::string& key,const std::string val)
      {
            headers_.insert(make_pair(key,val));
      }
      //判断是否存在指定头部字段
      bool HasHeader(const std::string& key)const
      {
            auto it=headers_.find(key);
            if(it==headers_.end())
            {
                  return false;
            }
            return true;
      }
      //获取指定头部字段的值
      std::string GetHeader(const std::string& key)const
      {
            auto it=headers_.find(key);
            if(it==headers_.end())
            {
                  return "";
            }
            return  it->second;     
      }
      //插入查询字符串
      void SetParam(const std::string& key,const std::string val)
      {
            params_.insert(make_pair(key,val));
      }
      //判断是否有某个指定的字符串
      bool HasParam(const std::string& key)const
      {
            auto it=params_.find(key);
            if(it==params_.end())
            {
                  return false;
            }
            return true;
      }
      //获取指定的查询字符串
      std::string GetParam(const std::string& key)const
      {
            auto it=params_.find(key);
            if(it==params_.end())   
            {
                  return "";
            }
            return  it->second;     
      }
      //获取正文长度
      size_t ContentLength()const
      {
         //Content-Length:1111\r\n
         bool ret=HasHeader("Content-Length");
         if(ret==false)    return 0;
         std::string len=GetHeader("Content-Length");
         return stol(len);
      }
      //判断是否短连接
      bool Close()const
      {
            //没有Connection字段，或者有Connection字段，但是值是close，则都是短连接，否则都是长连接
            if(HasHeader("Connection")&&GetHeader("Connection")=="keep-alive")
            {
                  return false;
            }
            return true;
      }
};

class HttpResponse
{
public:
      int statu_;
      bool redirect_flag_;
      std::string body_;
      std::string redirect_url_;
      std::unordered_map<std::string,std::string>     headers_;
public:
      HttpResponse():statu_(200),redirect_flag_(false)
      {}
      HttpResponse(int statu):statu_(statu),redirect_flag_(false)
      {}
      void ReSet()
      {
            statu_=200;
            redirect_flag_=false;
            body_.clear();
            redirect_url_.clear();
            headers_.clear();
      }
      //插入头部字段
      void SetHeader(const std::string& key,const std::string val)
      {
            headers_.insert(make_pair(key,val));
      }
      //判断是否存在指定头部字段
      bool HasHeader(const std::string& key)const
      {
            auto it=headers_.find(key);
            if(it==headers_.end())
            {
                  return false;
            }
            return true;
      }
      //获取指定头部字段的值
      std::string GetHeader(const std::string& key)const
      {
            auto it=headers_.find(key);
            if(it==headers_.end())
            {
                  return "";
            }
            return  it->second;     
      }
      void SetCotent(const std::string& body,const std::string& type="text/html")
      {
            body_=body;
            SetHeader("Content-Type",type);
      }
      void SetRedirect(const std::string& url,int statu=302)
      {
            statu_=statu;
            redirect_flag_=true;
            redirect_url_=url;
      }
      //判断是否短连接
      bool Close()const
      {
            //没有Connection字段，或者有Connection字段，但是值是close，则都是短连接，否则都是长连接
            if(HasHeader("Connection")&&GetHeader("Connection")=="keep-alive")
            {
                  return false;
            }
            return true;
      }
};

typedef enum
{
      RECV_HTTP_LINE,
      RECV_HTTP_HEAD,
      RECV_HTTP_BODY,
      RECV_HTTP_OVER,
      RECV_HTTP_ERROR
}HttpRecvStatu;

#define MAX_LINE 5555
class HttpContent
{
private:
      int resp_statu_;              //响应状态码
      HttpRecvStatu recv_statu_;    //当前接受和解析的阶段状态
      HttpRequest request_;         //已经解析得到的请求信息
private:
      bool ParseHttpLine(const std::string& line)
      {
            std::smatch matches;
            std::regex e("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?", std::regex::icase);
            bool ret=std::regex_match(line,matches,e);
            if(ret==false)
            {
                  recv_statu_=RECV_HTTP_ERROR;
                  resp_statu_=401;//bad request
                  return false;
            }
            //0 : GET /baidu.com/login?user=xiaoming&pass=123123 HTTP/1.1
            //1 : GET
            //2 : /baidu.com/login
            //3 : user=xiaoming&pass=123123
            //4 : HTTP/1.1

            //请求方法的获取
            request_.method_=matches[1];
            std::transform(request_.method_.begin(),request_.method_.end(),request_.method_.begin(),::toupper);
            //资源路径的获取，需要进行url解码操作，但是不需要将+转空格
            request_.path_=Util::UrlDecode(matches[2],false);
            //协议版本的获取
            request_.version_=matches[4];
            //查询字符串的获取与处理
            std::vector<std::string> v;
            Util::Split(matches[3],"&",&v);
            //针对各个子串，以=符号进行分割，得到key 和 val ,得到之后也需要进行URL解码
            for(auto& s:v)
            {
                  size_t pos=s.find('=');
                  if(pos==std::string::npos)
                  {
                        recv_statu_=RECV_HTTP_ERROR;
                        resp_statu_=401;//bad request
                        return false;
                  }
                  std::string key=Util::UrlDecode(s.substr(0,pos),true);
                  std::string val=Util::UrlDecode(s.substr(pos+1),true);
                  request_.SetParam( key,val);
            }
            return true;
      }
      bool RecvHttpLine(Buffer* buf)
      {
            if(recv_statu_!=RECV_HTTP_LINE)     return false;
            //1.获取一行数据，带有末尾的换行
            std::string line=buf->GetLineAndPop();
            //2.需要考虑的一些因素：缓冲区中的数据不足一行，获取的一行数据很大
            if(line.size()==0)
            {
                  //缓冲区的数量不足一行，则需要判断缓冲区的可读数据长度，如果很长了都不足一行，显然这是有问题的
                  if(buf->ReadAbleSize()>MAX_LINE)
                  {
                        recv_statu_=RECV_HTTP_ERROR;
                        resp_statu_=404;//url too long
                        return false;
                  }
                  //数据是有的，但是又不多，就慢慢等待数据的接受
                  return true;
            }
            if (line.size() > MAX_LINE)
            {
                  recv_statu_ = RECV_HTTP_ERROR;
                  resp_statu_ = 404;
                  return false;
            }
            bool ret=ParseHttpLine(line);
            if(ret==false)    return false;

            //首行处理完毕，进入头部获取阶段
            recv_statu_=RECV_HTTP_HEAD;
            return true;
      }
      bool ParseHttpHead(std::string line)
      {
            //key: val\r\nkey: val
            if(line.back()=='\n')   line.pop_back();//末尾是换行 则去掉
            if(line.back()=='\r')   line.pop_back();//末尾是回车 则去掉
            size_t pos=line.find(": ");
            if(pos==std::string::npos)
            {
                  recv_statu_ = RECV_HTTP_ERROR;
                  resp_statu_ = 400; //Head Parse error
                  return false;
            }
            std::string key=line.substr(0,pos);
            std::string val=line.substr(pos+2);
            request_.SetHeader(key,val);
            return true;
      }
      bool RecvHttpHead(Buffer* buf)
      {
            if(recv_statu_!=RECV_HTTP_HEAD)     return false;
            while(1)
            {
                  //1.获取一行数据，带有末尾的换行
                  std::string line=buf->GetLineAndPop();
                  //2.需要考虑的一些因素：缓冲区中的数据不足一行，获取的一行数据很大
                  if(line.size()==0)
                  {
                        //缓冲区的数量不足一行，则需要判断缓冲区的可读数据长度，如果很长了都不足一行，显然这是有问题的
                        if(buf->ReadAbleSize()>MAX_LINE)
                        {
                              recv_statu_=RECV_HTTP_ERROR;
                              resp_statu_=404;//url too long
                              return false;
                        }
                        //数据是有的，但是又不多，就慢慢等待数据的接受
                        return true;
                  }
                  if(line=="\n"||line=="\r\n")  break;
                  if (line.size() > MAX_LINE)
                  {
                        recv_statu_ = RECV_HTTP_ERROR;
                        resp_statu_ = 404;
                        return false;
                  }
                  bool ret=ParseHttpHead(line);
                  if(ret==false)    return false;
            }
            //首行处理完毕，进入正文获取阶段
            recv_statu_=RECV_HTTP_BODY;
            return true;
      }
      bool RecvHttpBody(Buffer* buf)
      {
            if(recv_statu_!=RECV_HTTP_BODY)     return false;
            //1.获取正文长度
            size_t len=request_.ContentLength();
            if(len==0)
            {
                  //没有正文，正文处理完毕
                  recv_statu_=RECV_HTTP_OVER;
                  return true;
            }
            //2.当前已经接受了多少正文，就是上次正文还没有给全
            size_t real_len=len-request_.body_.size();
            //3.接受正文放到body中，也要考虑当前缓冲区的数据，是否是全部的正文
            //3.1缓冲区的数据，包含了当前请求正文的全部数据，则取出所需要的数据
            if(buf->ReadAbleSize()>=real_len)
            {
                  request_.body_.append(buf->ReadPosition(),real_len);
                  buf->MoveReadOffset(real_len);
                  recv_statu_=RECV_HTTP_OVER;
                  return true;
            }
            //3.2缓冲区的数据无法满足正文的需要，取出数据，等待新数据到来
            request_.body_.append(buf->ReadPosition(),buf->ReadAbleSize());
            buf->MoveReadOffset(buf->ReadAbleSize());
            return true;
      }
public:
      HttpContent():resp_statu_(200),recv_statu_(RECV_HTTP_LINE)
      {}
      void ReSet()
      {
            resp_statu_=200;
            recv_statu_=RECV_HTTP_LINE;
            request_.ReSet();
      }
      int RespStatu()               {return resp_statu_;}
      HttpRecvStatu RecvStatu()     {return recv_statu_;}
      HttpRequest& Request()         {return request_;}
      //接受并解析HTTP请求
      void RecvHttpRequest(Buffer* buf)
      {
            //不同的状态，做不同的事，这里不用break，因为处理请求行后，应该立即处理头部
            switch(recv_statu_)
            {
                  case RECV_HTTP_LINE:RecvHttpLine(buf);
                  case RECV_HTTP_HEAD:RecvHttpHead(buf);
                  case RECV_HTTP_BODY:RecvHttpBody(buf);
            }
            return;
      }
};

#define DEFAULT_TIME 30
class HttpServer
{
private:
      using Handler=std::function<void(const HttpRequest&,HttpResponse*)>;
      using Handlers=std::vector<std::pair<std::regex,Handler>>; 
      Handlers get_route_;
      Handlers post_route_;
      Handlers put_route_;
      Handlers delete_route_;
      std::string basedir_;   //静态资源根目录
      TcpServer server_;      
private:
      void ErrorHandler(const HttpRequest& req,HttpResponse* rsp)
      {
            //组织一个错误展示页面
            std::string body;
            body += "<html>";
            body += "<head>";
            body += "<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>";
            body += "</head>";
            body += "<body>";
            body += "<h1>";
            body += std::to_string(rsp->statu_);
            body += " ";
            body += Util::StatuDesc(rsp->statu_);
            body += "</h1>";
            body += "</body>";
            body += "</html>";
            //将页面数据，当做响应正文，放进rsp中
            rsp->SetCotent(body,"text/html");
      }
      //将HttpResponse中的要素按照http协议格式进行组织，发送
      void WriteResponse(const PtrConnection& conn,const HttpRequest& req,HttpResponse& rsp)
      {
            //1.先完善头部
            if(req.Close()==true)   { rsp.SetHeader("Connection", "close");}
            else                    { rsp.SetHeader("Connection","keep-alive");}

            if(rsp.body_.empty()==false&&rsp.HasHeader("Content-Length")==false)
                                    { rsp.SetHeader("Content-Length",std::to_string(rsp.body_.size()));}

            if(rsp.body_.empty()==false&&rsp.HasHeader("Content-Type")==false)
                                    { rsp.SetHeader("Content-Type", "application/octet-stream");}
            if(rsp.redirect_flag_==true)
                                    { rsp.SetHeader("Location", rsp.redirect_url_);}

            //2.将rsp的要素，按照http格式组织
            std::stringstream rsp_str;
            rsp_str<<req.version_<<" "<<std::to_string(rsp.statu_)<<" "<<Util::StatuDesc(rsp.statu_)<<"\r\n";
            for(auto& head:rsp.headers_)
            {
                  rsp_str<<head.first<<": "<<head.second<<"\r\n";
            }
            rsp_str<<"\r\n";
            rsp_str<<rsp.body_;
            //3.发送数据
            conn->Send(rsp_str.str().c_str(),rsp_str.str().size());
      }
      bool IsFileHandler(const HttpRequest& req)
      {
            //1.必须设置了静态资源根目录
            if(basedir_.empty())                            return false;
            //2.请求方法，必须是GET/HEAD请求方法
            if(req.method_!="GET"&&req.method_!="HEAD")     return false;
            //3.请求的资源是合法路径
            if(Util::VaildPath(req.path_)==false)           return false;
            //4.请求的资源必须存在，且是一个普通文件
            //有一种请求比较特殊-----/,/image/,  这种情况默认给后边加一个 index.html
            std::string req_path=basedir_+req.path_;//防止直接修改请求的资源路径，定义一个临时对象
            if(req.path_.back()=='/')
                  req_path+="index.html";
            if(Util::IsRegular(req_path)==false)            return false;

            return true;
      }
      //静态资源的请求处理--将静态资源文件中的数据读取出来，放到rsp的body_中，并设置mime
      void FileHandler(const HttpRequest& req,HttpResponse* rsp)
      {
            std::string req_path=basedir_+req.path_;
            if(req.path_.back()=='/')
                  req_path+="index.html";
            bool ret=Util::ReadFile(req_path,&rsp->body_);
            if(ret==false)    return;
            std::string  mime=Util::ExtMime(req_path);
            rsp->SetHeader("Content-Type", mime);
            return;
      }
      //功能性请求的分类处理
      void Dispatcher(HttpRequest &req, HttpResponse *rsp, Handlers &handlers)
      {
            //在对应请求的路由表中，查找是否含有对应资源的请求的处理函数，有则调用，没有则发送404
            //思想：路由表存储的键值对：正则表达式 &处理函数
            //使用正则表达式，对请求的资源路径进行正则匹配，匹配成功就使用对应函数 处理
            //numbers/(\d+)   ==>numbers/12345
            for(auto& handler:handlers)
            {
                  const std::regex &r=handler.first;
                  const Handler& functor=handler.second;
                  bool ret=std::regex_match(req.path_,req.matches_,r);
                  if(ret==false)    continue;
                  return functor(req,rsp);
            }
            rsp->statu_=404;
      }
      void Route(HttpRequest &req, HttpResponse *rsp)
      {
            //1.对一个请求进行分辨，是一个静态资源处理还是一个功能性请求
            //1.1静态资源处理：进行静态的处理
            //1.2功能性请求：根据几个请求路由表确定是否有处理函数
            //1.3两者都不是，返回405
            if(IsFileHandler(req)==true)                    return FileHandler(req,rsp);
            if(req.method_=="GET"||req.method_=="HEAD")     return Dispatcher(req,rsp,get_route_);
            else if(req.method_=="POST")                    return Dispatcher(req,rsp,post_route_);
            else if(req.method_=="PUT")                     return Dispatcher(req,rsp,put_route_);
            else if(req.method_=="DELETE")                  return Dispatcher(req,rsp,delete_route_);
            rsp->statu_=405;
            return ;
      }
      //设置上下文
      void OnConnected(const PtrConnection& conn)
      {
            conn->SetContext(HttpContent());
            DBG_LOG("NEW CONNECTION:%p",conn.get());
      }
      //缓冲区数据解析+处理
      void OnMessage(const PtrConnection& conn,Buffer* buf)
      {
            while(buf->ReadAbleSize())
            {
                  //1.获取上下文
                  HttpContent* context=conn->GetContext()->get<HttpContent>();
                  //2.通过上下文对缓冲区数据进行解析，得到HttpRequest对象
                  //2.1 如果缓冲区的数据解析出错，就直接回复出错响应
                  //2.2 如果解析正常，且请求已经获取完毕，才开始去进行处理
                  context->RecvHttpRequest(buf);
                  HttpRequest &req=context->Request();
                  HttpResponse rsp(context->RecvStatu());
                  if(context->RespStatu()>=400)
                  {
                        //运行错误响应，关闭连接
                        ErrorHandler(req,&rsp);                 //填充一个错误显示页面数据到rsp中
                        WriteResponse(conn,req,rsp);             //    组织响应发送给客户端
                        context->ReSet();
                        buf->MoveReadOffset(buf->ReadAbleSize()); //出错了就把缓冲区数据清空
                        conn->Shutdown();                         //关闭连接
                        return;
                  }
                  if(context->RecvStatu()!=RECV_HTTP_OVER)
                  {
                        //数据还没有处理完，退出，等待新数据到来再重修处理
                        return;
                  }
                  //3.请求路由+业务处理
                  Route(req,&rsp);
                  //4.对HttpResponse进行组织发送
                  WriteResponse(conn,req,rsp); 
                  //5.重置上下文
                  context->ReSet();
                  //6.根据长短连接判断是否关闭连接还是继续处理
                  if(rsp.Close()==true)   conn->Shutdown();  
            }
            return;
      }
public:
      HttpServer(int port,int timeout=DEFAULT_TIME)
            :server_(port)
      {
            server_.EnableInactiveRelease(timeout);
            server_.SetConnectedCallback(std::bind(&HttpServer::OnConnected,this,std::placeholders::_1));
            server_.SetMessageCallback(std::bind(&HttpServer::OnMessage,this,std::placeholders::_1,std::placeholders::_2));
      }
      void SetBaseDir(const std::string& path)
      {
            assert(Util::IsDirectory(path)==true);
            basedir_=path;
      }
      //添加正则表达式与处理函数的映射关系
      void Get(const std::string &pattern,const Handler& handler)
      {
            get_route_.push_back(std::make_pair(std::regex(pattern),handler));
      }
      void Put(const std::string &pattern,const Handler& handler)
      {
            put_route_.push_back(std::make_pair(std::regex(pattern),handler));
      }
      void Post(const std::string &pattern,const Handler& handler)
      {
            post_route_.push_back(std::make_pair(std::regex(pattern),handler));
      }
      void Delete(const std::string &pattern,const Handler& handler)
      {
            delete_route_.push_back(std::make_pair(std::regex(pattern),handler));
      }
      void SetThreadCount(int count)
      {
            server_.SetThreadCount(count);
      }
      void Listen()
      {
            server_.Start();
      }
};